﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Configuration;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using Time.BLL;
using Time.Foramework;
using Time.IBLL;
using Time.OPCServerV;

namespace WinZTTMES
{
    public partial class MainForm : Form
    {
        //plc操作对象
        private OpcBusiness opc;
        //获取全部数据
        IEqAlarm_BLL objIEqAlarm_BLL = new EqAlarm_BLL();
        //初始化返回信息是否初始化成功
        bool OpcConnectBl = false;

        //扫描枪1  扫描电池码11  数据存储
        static byte[] receive11 = new byte[100];
        //扫描枪1  扫描电池码12  数据存储
        static byte[] receive12 = new byte[100];
        //扫描枪1  扫描托盘码13  数据存储   电池托盘绑定
        static byte[] receive13 = new byte[100];
        //扫描枪1  扫描托盘码14  数据存储   一号线上料
        static byte[] receive14 = new byte[100];
        //扫描枪1  扫描托盘码15  数据存储   二号线上料
        static byte[] receive15 = new byte[100];
        //配置文件地址
        public static string configPath;
        //获取配置信息应该分为两个设备驱动
        private static string ChanneOtherDevice = ConfigurationManager.AppSettings["ChanneOtherDevice"].ToString();
        private static string ChanneScanCodeDevice = ConfigurationManager.AppSettings["ChanneScanCodeDevice"].ToString();

        //失败计数  用于重启线程
        int indexFlage13 = 0;
        int indexFlage14 = 0;
        int indexFlage15 = 0;

        public MainForm()
        {
            InitializeComponent();
        }
        /*********************
         * sky
         * 主Form加载信息
         * **********************/
        private void MainForm_Load(object sender, EventArgs e)
        {
            configPath = Application.StartupPath + "\\Config.ini";

            //查询配置PLC的地址
            DataTable objDt = objIEqAlarm_BLL.getDataTable("ZTT_EqStationCode");
            //用于存放PLC地址
            List<string> lstItem = new List<string>();
            //遍历地址添加到集合中
            for (int i = 0; i < objDt.Rows.Count; i++)
            {
                for (int c = 2; c < objDt.Columns.Count; c++)
                {
                    if (!string.IsNullOrEmpty(objDt.Rows[i][c].ToString()))
                    {
                        lstItem.Add(ChanneOtherDevice + objDt.Rows[i][c].ToString());
                        lstItem.Add(ChanneScanCodeDevice + objDt.Rows[i][c].ToString());
                    }
                    
                }
            }
            

            lstItem.Add("Channel1.Device2.D02524");
            lstItem.Add("Channel1.Device2.D02525");
            lstItem.Add("Channel1.Device2.D02526");
            lstItem.Add("Channel1.Device2.D02527");
            lstItem.Add("Channel1.Device2.D02528");
            lstItem.Add("Channel1.Device1.D02528");


            //连接OPCServer并初始化OPC连接
            opc = OpcBusiness.GetInstance();

            string errorStr = null;
            OpcConnectBl = opc.Init(lstItem, ref errorStr); 
            //线程里启动初始化连接扫描枪
            Thread thread = new Thread(new ThreadStart(initScanning));
            thread.Start();

            
            Thread thread2 = new Thread(new ThreadStart(updataPLCData));
            thread2.Start();

            Thread thread3 = new Thread(new ThreadStart(showPLCData));
            thread3.Start();
        }
        
        /******************
         * sky
         * 双击图标展示窗口
         * ******************/
        private void notifyIcon1_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            this.Show();
        }
        
        /*******************
         * sky
         * 关闭程序最小化到任务栏
         * *****************/
        private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            e.Cancel = true;
            this.Hide();
            this.notifyIcon1.Visible = true;
        }

        /******************
         * sky
         * 右键程序的图标会有三个选项：显示窗口、隐藏窗口、退出程序
         * 第一个显示窗口
         * *****************/
        private void toolStripMenuItem1_Click(object sender, EventArgs e)
        {
            this.Show();
            this.WindowState = FormWindowState.Normal;
            this.Activate();
        }

        /*******************
         * sky
         * 第二个选项：隐藏窗口
         * *****************/
        private void toolStripMenuItem2_Click(object sender, EventArgs e)
        {
            this.Hide();
        }
        /*******************
         * sky
         * 第三个询问是否退出程序
         * *****************/
        private void toolStripMenuItem3_Click(object sender, EventArgs e)
        {
            if (MessageBox.Show("确定要退出程序？", "安全提示", System.Windows.Forms.MessageBoxButtons.YesNo,
                System.Windows.Forms.MessageBoxIcon.Warning) == System.Windows.Forms.DialogResult.Yes)
            {
                try
                {
                    //  notifyIcon1.Visible = false;//系统托盘图标不可见
                    this.Dispose();//释放资源
                    notifyIcon1.Dispose();
                    this.Close();//关闭窗体 
                    Application.Exit();//关闭应用程序窗体 
                    Application.ExitThread(); //强制中止调用线程上的所有消息，同样面临其它线程无法正确退出的问题；
                    System.Environment.Exit(0); //这是最彻底的退出方式，不管什么线程都被强制退出，把程序结束的很干净。
                }
                catch (Exception ex)
                {

                }
                finally
                {
                    GC.Collect();
                }
            }
        }
        /*********************
         * sky
         * 初始化扫描枪IP地址
         * *************************/
        private void initScanning()
        {
            //启动扫描监听
            string ipAdress11 = "192.168.3.11";
            int port = 2001;
            startScanning(ipAdress11, port, 11);

            string ipAdress12 = "192.168.3.12";
            startScanning(ipAdress12, port, 12);

            string ipAdress13 = "192.168.3.13";
            startScanning(ipAdress13, port, 13);

            string ipAdress14 = "192.168.3.14";
            startScanning(ipAdress14, port, 14);

            string ipAdress15 = "192.168.3.15";
            startScanning(ipAdress15, port, 15);
        }

        /*****************
         * sky
         * 开启扫码枪数据获取接收功能
         * 电池扫描 11
         * 参数：
         * 扫码枪地址  ipAdress  string
         * 端口号      port      int
         * 标志位      flage   -- 11电池扫描1   12电池扫描2   13托盘扫描
         * *********************/
        private void startScanning(string ipAdress,int port,int flage)
        {
            try
            {
                IPAddress ip = IPAddress.Parse(ipAdress);  //将IP地址字符串转换成IPAddress实例
                Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);//使用指定的地址簇协议、套接字类型和通信协议
                IPEndPoint endPoint = new IPEndPoint(ip, port); // 用指定的ip和端口号初始化IPEndPoint实例
                socket.Connect(endPoint);  //与远程主机建立连接
                switch (flage)
                {
                    case 11:
                        socket.BeginReceive(receive11, 0, 26, SocketFlags.None, new AsyncCallback(ReceiveMessage11), socket);
                        break;
                    case 12:
                        socket.BeginReceive(receive12, 0, 26, SocketFlags.None, new AsyncCallback(ReceiveMessage12), socket);
                        break;
                    case 13:
                        socket.BeginReceive(receive13, 0, 10, SocketFlags.None, new AsyncCallback(ReceiveMessage13), socket);
                        break;
                    case 14:
                        socket.BeginReceive(receive14, 0, 8, SocketFlags.None, new AsyncCallback(ReceiveMessage14), socket);
                        break;
                    case 15:
                        socket.BeginReceive(receive15, 0, 8, SocketFlags.None, new AsyncCallback(ReceiveMessage15), socket);
                        break;
                    default:
                        //此处为非法输入
                        break;
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("连接扫码枪失败" + ipAdress);
            }
            
        }
        /*********************************************回调函数  通知PLC扫描成功***********************************************/
        //plc对象默认值
        int iErr = -1;
        /*****************
         * 回调
         * 判断数据是否获取成功
         * 电池码11
         * 成功通知PLC
         * ********************/
        private void ReceiveMessage11(IAsyncResult ar)
        {
            try
            {
                var socket = ar.AsyncState as Socket;
                var length = socket.EndReceive(ar);
                var indextstring = Encoding.ASCII.GetString(receive11, 0, 26);
                //去掉换行回车符
                string message = indextstring.ToString().Replace("\0", "").Replace("\n", "").Replace(" ", "").Replace("\t", "").Replace("\r", "");
                //输出字符长度
                Console.WriteLine("接收消息为长度为：" + message.Trim().Length);
                Console.WriteLine("接收消息为：" + message.Trim());
                string scanStatus = "1";

                if (message.Trim().Length == 24)
                {
                    string searchStrSql = string.Format("select * from ZTT_TrayBatteryRelation where batteryCoder = '{0}'", message.Trim());

                    DataTable objTempDt = objIEqAlarm_BLL.getData(searchStrSql);
                    //判断电池是否重复
                    if (objTempDt.Rows.Count == 0)
                    {
                        dataGridView1.Invoke(new Action(() =>
                            dataGridView1.Rows.Add(trayNumber.Text, message, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"))
                        ));
                        new DataBaseOperate().loadDate(string.Format("insert into ZTT_TrayBatteryRelation (palletNumber,batteryCoder)values('{0}','{1}')", trayNumber.Text,
                         message.Trim()));
                        opc.WriteData("D02524", scanStatus, ref iErr, "Channel1.", "Device2.");
                        showDataMessage("电池1号" + message + "获取成功\n");
                    }
                    else
                    {
                        //通知PLC数据失败
                        opc.WriteData("D02524", "2", ref iErr, "Channel1.", "Device2.");
                        showDataMessage("电池1号" + message + "重复扫码\n");
                    }
                    Thread.Sleep(300);
                    socket.BeginReceive(receive11, 0, 26, SocketFlags.None, new AsyncCallback(ReceiveMessage11), socket);
                }
                else
                {
                    Thread.Sleep(3000);
                    socket.Close();
                }
                
            }
            catch (Exception ex)
            {
                //数据失败
                showDataMessage("电池1号扫描枪连接失败\n");
            }
        }
        /*****************
         * 回调
         * 判断数据是否获取成功
         * 成功通知PLC
         * ********************/
        private void ReceiveMessage12(IAsyncResult ar)
        {
            try
            {
                var socket = ar.AsyncState as Socket;
                var length = socket.EndReceive(ar);
                var indextstring = Encoding.ASCII.GetString(receive12, 0, 26);
                string message = indextstring.ToString().Replace("\0", "").Replace("\n", "").Replace(" ", "").Replace("\t", "").Replace("\r", "");

                Console.WriteLine("接收消息为长度为：" + message.Trim().Length);
                Console.WriteLine("接收消息为：" + message.Trim());
                string scanStatus = "1";
                //显示在grid中
                
                if (message.Trim().Length == 24)
                {
                    string searchStrSql = string.Format("select * from ZTT_TrayBatteryRelation where batteryCoder = '{0}'", message.Trim());

                    DataTable objTempDt = objIEqAlarm_BLL.getData(searchStrSql);
                    //判断电池是否重复
                    if (objTempDt.Rows.Count == 0)
                    {
                        dataGridView1.Invoke(new Action(() =>
                            dataGridView1.Rows.Add(trayNumber.Text, message, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"))
                        ));
                        //添加到数据库中
                        new DataBaseOperate().loadDate(string.Format("insert into ZTT_TrayBatteryRelation (palletNumber,batteryCoder)values('{0}','{1}')", trayNumber.Text,
                         message.Trim()));
                        opc.WriteData("D02525", scanStatus, ref iErr, "Channel1.", "Device2.");
                        showDataMessage("电池2号" + message + "获取成功\n");
                    }
                    else
                    {
                        opc.WriteData("D02525", "2", ref iErr, "Channel1.", "Device2.");
                        showDataMessage("电池2号" + message + "重复扫码\n");
                    }
                        
                }
                Thread.Sleep(300);
                socket.BeginReceive(receive12, 0, 26, SocketFlags.None, new AsyncCallback(ReceiveMessage12), socket);
            }
            catch (Exception ex)
            {
                //数据失败
                showDataMessage("电池2号扫描枪连接失败\n");
            }
        }
        /*****************
         * 回调
         * 判断数据是否获取成功
         * 成功通知PLC
         * ********************/
        private void ReceiveMessage13(IAsyncResult ar)
        {
            try
            {
                var socket = ar.AsyncState as Socket;
                var length = socket.EndReceive(ar);
                var indextstring = Encoding.ASCII.GetString(receive13, 0, 8);
                string messageRev = indextstring.ToString().Replace("\0", "").Replace("\n", "").Replace(" ", "").Replace("\t", "").Replace("\r", "");

                Console.WriteLine("接收消息为：" + messageRev.Trim());
                string scanStatus = "1";

                if (messageRev.StartsWith("TP"))
                {
                    string message = "";
                    if (messageRev.Length >= 6)
                    {
                        message = messageRev.Substring(0,6);
                    }

                    if (message.Length == 6)
                    {
                        indexFlage13 = 0;
                        opc.WriteData("D02526", scanStatus, ref iErr, "Channel1.", "Device2.");
                        //显示在文本框里面
                        trayNumber.BeginInvoke(new Action(() =>
                            trayNumber.Text = message
                        ));
                        showDataMessage("电池托盘号" + message + "获取成功\n");
                    }
                }
                else
                {
                    //连续三次获取数据不成功重新启动线程
                    if (indexFlage13 >= 3)
                    {
                        socket.Close();
                        Thread.Sleep(1000);
                        string ipAdress13 = "192.168.3.13";
                        startScanning(ipAdress13, 2001, 13);
                        Console.WriteLine("----->线程重新启动<-------");
                        return;
                    }
                    indexFlage13++;
                    //opc.WriteData("D02526", "2", ref iErr, "Channel1.", "Device2.");
                }
                Thread.Sleep(300);
                socket.BeginReceive(receive13, 0, 8, SocketFlags.None, new AsyncCallback(ReceiveMessage13), socket);

            }
            catch (Exception ex)
            {
                //数据失败
                showDataMessage("电池托盘扫描枪连接失败\n");
            }
        }
        /*****************
         * 回调
         * 判断数据是否获取成功
         * 成功通知PLC
         * ********************/
        private void ReceiveMessage14(IAsyncResult ar)
        {
            try
            {
                var socket = ar.AsyncState as Socket;
                var length = socket.EndReceive(ar);
                var indextstring = Encoding.ASCII.GetString(receive14, 0, 8);
                string messageRev = indextstring.ToString().Replace("\0", "").Replace("\n", "").Replace(" ", "").Replace("\t", "").Replace("\r", "");

                
                Console.WriteLine("接收消息为：" + messageRev.Trim());
                string scanStatus = "1";
                if (messageRev.StartsWith("TP"))
                {
                    string message = "";
                    if (messageRev.Length >= 6)
                    {
                        message = messageRev.Substring(0, 6);
                    }

                    if (message.Trim().Length == 6)
                    {
                        indexFlage14 = 0;
                        dataGridView2.Invoke(new Action(() =>
                                dataGridView2.Rows.Add("小车号", message, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"))
                            ));
                        //添加到数据库中
                        new DataBaseOperate().loadDate(string.Format("insert into ZTT_TrayCarRelation (palletNumber,carNumber,assLineNumber)values('{0}','{1}','{2}')", message.Trim(),
                         "小车号", "生产一线"));
                        opc.WriteData("D02527", scanStatus, ref iErr, "Channel1.", "Device2.");
                        showDataMessage("生产一线托盘号" + message + "获取成功\n");
                    }
                }
                else
                {
                    //连续三次获取数据不成功重新启动线程
                    if (indexFlage14 >= 3)
                    {
                        socket.Close();
                        Thread.Sleep(1000);
                        string ipAdress14 = "192.168.3.14";
                        startScanning(ipAdress14, 2001, 14);
                        Console.WriteLine("----->线程重新启动14<-------");
                        return;
                    }
                    indexFlage14++;
                    //opc.WriteData("D02527", "2", ref iErr, "Channel1.", "Device2.");
                }
                
                Thread.Sleep(300);
                socket.BeginReceive(receive14, 0, 8, SocketFlags.None, new AsyncCallback(ReceiveMessage14), socket);
            }
            catch (Exception ex)
            {
                //数据失败
                showDataMessage("生产一线扫描枪连接失败\n");
            }
        }
        /*****************
         * 回调
         * 判断数据是否获取成功
         * 成功通知PLC
         * ********************/
        private void ReceiveMessage15(IAsyncResult ar)
        {
            try
            {
                var socket = ar.AsyncState as Socket;
                var length = socket.EndReceive(ar);
                var indextstring = Encoding.ASCII.GetString(receive15, 0, 8);
                string messageRev = indextstring.ToString().Replace("\0", "").Replace("\n", "").Replace(" ", "").Replace("\t", "").Replace("\r", "");
                
                Console.WriteLine("接收消息为：" + messageRev.Trim());
                string scanStatus = "1";
                if (messageRev.StartsWith("TP"))
                {
                    string message = "";
                    if (messageRev.Length >= 6)
                    {
                        message = messageRev.Substring(0, 6);
                    }
                    if (message.Trim().Length == 6)
                    {
                        indexFlage15 = 0;
                        dataGridView2.Invoke(new Action(() =>
                            dataGridView2.Rows.Add("小车号", message, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"))
                        ));
                        //添加到数据库中
                        new DataBaseOperate().loadDate(string.Format("insert into ZTT_TrayCarRelation (palletNumber,carNumber,assLineNumber)values('{0}','{1}','{2}')", message.Trim(),
                         "小车号", "生产二线"));
                        opc.WriteData("D02528", scanStatus, ref iErr, "Channel1.", "Device1.");
                        showDataMessage("生产二线托盘号" + message + "获取成功\n");
                    }
                }
                else
                {
                    //连续三次获取数据不成功重新启动线程
                    if (indexFlage15 >= 3)
                    {
                        socket.Close();
                        Thread.Sleep(1000);
                        string ipAdress15 = "192.168.3.15";
                        startScanning(ipAdress15, 2001, 15);
                        Console.WriteLine("----->线程重新启动15<-------");
                        return;
                    }
                    indexFlage15++;
                    //opc.WriteData("D02528", "2", ref iErr, "Channel1.", "Device2.");
                }
                
                Thread.Sleep(300);
                socket.BeginReceive(receive15, 0, 8, SocketFlags.None, new AsyncCallback(ReceiveMessage15), socket);
            }
            catch (Exception ex)
            {
                //数据失败
                showDataMessage("生产二线扫描枪连接失败\n");
            }
        }

        /*******************
         * sky
         * 读取PLC数据更新到数据库
         * ********************/
        public void updataPLCData()
        {
            while (true)
            {
                string tempStrSql = "";
                //获取所有工位数据
                DataTable objDt = objIEqAlarm_BLL.getDataTable("ZTT_EqStationCode");
                for (int i = 0; i < objDt.Rows.Count; i++)
                {
                    if (i >= objDt.Rows.Count)
                    {
                        break;
                    }
                    tempStrSql = "insert into ZTT_EqStationInfo (工位,小车流水号 ,温度SV,温度测量值PV1,温度测量值PV2,真空度低限SV,真空度高限SV ,真空度PV,采集时间)values(";

                    tempStrSql += "'" + objDt.Rows[i]["工位"].ToString() + "'";
                    //遍历PLC地址  获取PLC数据
                    for (int c = 2; c < objDt.Columns.Count; c++)
                    {
                        try
                        {
                            if (!string.IsNullOrEmpty(objDt.Rows[i][c].ToString()))
                            {
                                string aaa = objDt.Rows[i][c].ToString();
                                var receiveData = opc.ReadData(ChanneOtherDevice + objDt.Rows[i][c].ToString());
                                if (c == 2)
                                {
                                    //此处获取小车号
                                    //获取小车号地址 此处可能需要多个地址吗进行组合
                                    string SmallCarNo = null;
                                    string ReadPLCSmallCard = objDt.Rows[i][c].ToString().Substring(0, objDt.Rows[i][c].ToString().Length - 1);
                                    //获取PLC小车号
                                    for (int k = 0; k < 10; k++)
                                    {
                                        string PLCAddress = ReadPLCSmallCard;
                                        PLCAddress += k.ToString();
                                        var receiveDataSM = opc.ReadData(ChanneOtherDevice + PLCAddress);
                                        try
                                        {
                                            //ASCII转化为字符
                                            int AscciiData = Convert.ToInt32(Convert.ToInt32(receiveDataSM) % 256);
                                            SmallCarNo += ASCIIConvertString.Chr(AscciiData);
                                            AscciiData = Convert.ToInt32(Convert.ToInt32(receiveDataSM) / 256);
                                            SmallCarNo += ASCIIConvertString.Chr(AscciiData);
                                        }
                                        catch (Exception exs)
                                        {
                                            //数据获取失败
                                        }
                                    }
                                    //把数据组合到SQL中
                                    //tempStrSql += string.Format(",'{0}'", SmallCarNo);
                                    tempStrSql += string.Format(",'{0}'", "小车号");
                                }
                                else
                                {
                                    //此处获取温度真空度等其他值
                                    if (c == 3 || c == 4)
                                    {
                                        double myTem = Convert.ToDouble(receiveData);
                                        string currTem = myTem / 10 + "";
                                        tempStrSql += string.Format(",'{0}'", currTem);
                                    }
                                    else
                                    {
                                        tempStrSql += string.Format(",'{0}'", Convert.ToString(receiveData));
                                    }
                                    
                                }
                            }
                            //此处是没有数据需要添加空值
                            //以后需要删除
                            else
                            {
                                tempStrSql += string.Format(",'{0}'", "");
                            }
                        }
                        catch (Exception ex)
                        {

                        }
                        
                    }
                    tempStrSql += string.Format(",'{0}')", DateTime.Now.ToString());
                    int result = objIEqAlarm_BLL.ExecuteNonQuery(tempStrSql, null);
                }
                Thread.Sleep(30000);
            }
        }

        /****************************
         * sky
         * 展示工艺数据
         * *******************************/
        private void showPLCData()
        {
            while (true)
            {
                //DataTable objDtPlcData = objIEqAlarm_BLL.getDataTable("ZTT_EqStationInfo");
                DataTable objDtPlcData = new DataBaseOperate().loadDate("select t1.工位,t1.温度SV,t1.温度测量值PV1,t1.真空度低限SV,t1.真空度高限SV,t1.真空度PV,t1.采集时间 from ZTT_EqStationInfo t1 "+
                    "left join ZTT_EqStationCode t3 on t1.工位 = t3.工位 "+
                    "where t1.采集时间 in (select max(t2.采集时间) from ZTT_EqStationInfo t2 group by t2.工位) "+
                    "order by t3.Item ");
                dataGridView3.Invoke(new Action(() =>
                    dataGridView3.DataSource = objDtPlcData.DefaultView
                ));
                Thread.Sleep(60000);
            }
        }
        private void showDataMessage(string messageinfo)
        {
            //显示在文本框里面
            messageText.BeginInvoke(new Action(() =>
                messageText.AppendText(messageinfo + "\n" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "\n")
            ));
        }

    }
}
